/**
 * @file        application.cpp
 * @brief       Defines the GTD application barebones.
 *
 * @author      Emre Turkay <emreturkay at gmail>
 * @date        Jun.04.2008
 */

#include "application.hpp"
#include "interface.hpp"
#include "gtd.hpp"

application::application(interface& intf, gtd::gtd& backend)
    : quit_(false),
      intf_(intf),
      backend_(backend)
{
    intf_.command("help", boost::bind(&application::help, this, _1),
                  "Show this help screen.");
    intf_.command("next", boost::bind(&application::next, this, _1),
                  "Show next action.");
    intf_.command("done", boost::bind(&application::done, this, _1),
                  "Mark the current action as done.");
    intf_.command("cancel", boost::bind(&application::cancel, this, _1),
                  "Cancel the current action.");
    intf_.command("defer", boost::bind(&application::defer, this, _1),
                  "Defer the current action.");
    intf_.command("append", boost::bind(&application::append, this, _1),
                  "Append item given in quotes.");
    intf_.command("prepend", boost::bind(&application::prepend, this, _1),
                  "Prepend item given in quotes.");
    intf_.command("list", boost::bind(&application::list, this, _1),
                  "Lists the projects. If a project given lists the items.");
    intf_.command("quit", boost::bind(&application::quit, this, _1),
                  "Leave the gtdshell.");
}

void application::run()
{
    prompt();

    while (!quit_)
        if (!intf_.process())
            quit_ = true;
}

void application::help(const interface::args_type&)
{
    intf_.help();
}

void application::next(const interface::args_type&)
{
    prompt();
}

void application::done(const interface::args_type&)
{
    backend_.done();
    intf_.out() << "done." << std::endl;
    prompt();
}

void application::cancel(const interface::args_type&)
{
    backend_.cancel();
    intf_.out() << "cancelled." << std::endl;
    prompt();
}

void application::defer(const interface::args_type&)
{
    backend_.defer();
    intf_.out() << "deferred." << std::endl;
    prompt();
}

void application::list(const interface::args_type& args)
{
    if (args.size() == 0)
    {
        interface::args_type l = backend_.project_names();
        if (l.empty())
            intf_.out() << "There is no project." << std::endl;
        else
            for (interface::args_type::const_iterator i = l.begin();
                 i != l.end(); ++i)
            {
                boost::optional<gtd::gtd::project_id> id =
                    backend_.find_project(*i);
                if (!id)
                    intf_.out() << "There is no such project." << std::endl;
                else
                {
                    size_t count = backend_.item_count(*id);
                    intf_.out() << *i << " (" << count << ')' << std::endl;
                }
            }
    }
    else if ((args.size() == 1) && (args[0][0] == '+'))
    {
        std::string project_name(args[0].begin() + 1, args[0].end());
        boost::optional<gtd::gtd::project_id> id =
            backend_.find_project(project_name);
        if (!id)
            intf_.out() << "There is no such project." << std::endl;
        else
        {
            std::list<size_t> l = backend_.items(*id);
            size_t n = 1;
            for (std::list<size_t>::const_iterator i = l.begin();
                 i != l.end(); ++i, ++n)
            {
                const gtd::action& action = backend_.item(*id, *i);
                intf_.out() << '[' << n << "] " << action.description()
                            << std::endl;
            }
        }
    }
    else
    {
        intf_.out() << "Usage: list +project_name" << std::endl;
    }
}

void application::quit(const interface::args_type&)
{
    quit_ = true;
    intf_.out() << "bye." << std::endl;
}

void application::append(const interface::args_type& args)
{
    if (args.size() != 1)
    {
        intf_.out() << "Usage: append value" << std::endl;
    }
    else
    {
        backend_.append(args[0]);
        intf_.out() << "Added." << std::endl;
    }
}

void application::prepend(const interface::args_type& args)
{
    if (args.size() != 1)
    {
        intf_.out() << "Usage: prepend value" << std::endl;
    }
    else
    {
        backend_.prepend(args[0]);
        intf_.out() << "Added." << std::endl;
    }
}

void application::prompt()
{
    if (!backend_.empty())
    {
        const gtd::project& p = backend_.get_project(backend_.top_project());
        const gtd::action& a = p.item(p.top());

        intf_.out() << "next: ";
        if (p.name())
            intf_.out() << '+' << *(p.name()) << ' ';

        intf_.out() << a.description() << std::endl;
    }
    else
        intf_.out() << "no items in the queue." << std::endl;
}

